/*
 * lista.c
 *
 *  Created on: 04/09/2011
 *      Author: guido
 */

#include "lista.h"
#include "iterador.h"
#include "string.h"
#include "usuario.h"
#include <stdlib.h>

struct Usuario;
void Lista_init(Lista* l) {
	l->raiz = 0;
}

Iterador Lista_iterador(Lista* l) {
	Iterador it;
	It_init(&it, l);
	return it;
}

/* Pre: usuario debe apuntar a una instancia de Usuario valida.
 * No se haran chequeos con esto
 * Post: agregar inserta el usuario especificado exactamente
 * antes del primer nodo cuya clave sea mayor a la del usuario
 * especificado. La lista siempre queda ordenada */
void Lista_agregar(Lista* l, Usuario* usuarioNuevo) {
	Nodo* nuevo = Lista_crearNodo(usuarioNuevo);
	Nodo* anterior = NULL;
	Nodo* siguiente = l->raiz;
	int mayorAlSiguiente = 0;
	while ((siguiente != NULL) && !(mayorAlSiguiente)) {
		if (strcmp(usuarioNuevo->numero, siguiente->usuario->numero) < 0)
			mayorAlSiguiente = 1;
		else {
			anterior = siguiente;
			siguiente = siguiente->nodoSiguiente;
		}
	}
	if (anterior == NULL
		)
		l->raiz = nuevo;
	else
		anterior->nodoSiguiente = nuevo;
	nuevo->nodoSiguiente = siguiente;
}

/* Devuelve un iterador en la posicion del nodo buscado (si lo encontro
 * Chequear luego con It_tieneSiguiente(..). Si devuelve positivo,
 * sí se encontró el nodo. */
Iterador Lista_buscar(Lista* l, char* numUsuario) {
	Iterador it = Lista_iterador(l);
	int encontrado = 0;
	Usuario* usuario;
	while ((It_tieneSiguiente(&it)) && !(encontrado)) {
		usuario = It_get(&it);
		if (strcmp(usuario->numero, numUsuario) == 0)
			encontrado = 1;
		else
			It_siguiente(&it);
	}
	return (it);
}

struct Usuario* Lista_removerUsuario(Lista* l, char* numero) {
	Iterador it = Lista_buscar(l, numero);
	Usuario* usuario = It_remover(&it);
	return usuario;
}

/* Funciona como un copiarLista normal, solo que chequea que los
 * usuario a agregar no coincidan con el especificado, y que tampoco
 * sean amigos */
void Lista_agregarListaDePosibles(Lista* datos, Lista* novedades,
		Usuario* usuario) {
	Iterador it = Lista_iterador(novedades);
	while ( It_tieneSiguiente(&it) ) {
		Usuario* usuarioNuevo = It_siguiente(&it);
		if ( !Usuario_esAmigo(usuario, usuarioNuevo) &&
			 (strcmp(usuario->numero, usuarioNuevo->numero) != 0) ) {
			Lista_agregar(datos, usuarioNuevo);
		}
	}
}

/* Dado que la lista esta ordenada, esta función compara nodos
 * adyacentes. Si referencian al mismo usuario, se borra el nodo */
void Lista_borrarDuplicados(Lista* l) {
	Nodo* anterior = l->raiz;
	Nodo* siguiente = NULL;
	if (l->raiz != NULL)
		siguiente = l->raiz->nodoSiguiente;
	while ( siguiente != NULL ) {
		if (strcmp(anterior->usuario->numero,
				siguiente->usuario->numero) == 0) {
			Nodo* nodoABorrar = siguiente;
			siguiente = siguiente->nodoSiguiente;
			anterior->nodoSiguiente = siguiente;
			free(nodoABorrar);
		}
		else {
			anterior = siguiente;
			siguiente = siguiente->nodoSiguiente;
		}
	}
}

void Lista_destroy(Lista* l) {
	Nodo* actual = l->raiz;
	while (actual != NULL) {
		Nodo* siguiente = actual->nodoSiguiente;
		free(actual);
		actual = siguiente;
	}
}

Nodo* Lista_crearNodo(struct Usuario* usuario) {
	Nodo* nuevo = malloc(sizeof(Nodo));
	Nodo_init(nuevo, usuario);
	return nuevo;
}
